package com.educate.common.filter;


import com.educate.common.web.JsonUtils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;

@Aspect
@Log4j2
public class DefaultWebLogAspect {

    private ThreadLocal<StringBuilder> threadStringBuilder = new ThreadLocal<>();

    private ObjectMapper mapper;

    {
        mapper = new ObjectMapper();
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        JsonUtils.setObjectMapper(mapper);
    }

    public StringBuilder getThreadStringBuilder() {
        StringBuilder instance = threadStringBuilder.get();
        if (null == instance) {
            instance = new StringBuilder();
            threadStringBuilder.set(instance);
        }
        return instance;
    }

    @Pointcut("execution(public * com.educate.*.web.controller.*.*(..))")
    public void webLog() {
    }

    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        StringBuilder sb = getThreadStringBuilder();
        sb.delete(0, sb.length());
        sb.append("\n\n\n=== ").append(request.getRequestURI()).append("\n\n").append("----\n");
        sb
                .append("path:").append(request.getRequestURI()).append("\n")
//                .append("ip:").append(request.getRemoteAddr()).append("\n")
                .append("method:").append(request.getMethod()).append("\n")
                .append("-------param------\n");
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            if (arg instanceof ServletRequest || arg instanceof ServletResponse) {
                continue;
            }
            try {
                String param = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(arg);
                sb.append(param).append("\n");
            } catch (Exception e) {
                sb.append("unkown type").append(arg.getClass()).append("\n");
            }
        }
//        log.debug(sb);
    }

    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        StringBuilder sb = getThreadStringBuilder();
        try {
            String param = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(ret);
            sb.append("-----return-----\n").append(param);
        } catch (Exception e) {
//            e.printStackTrace();
//            log.debug("return:unkown type " + ret.getClass());
            sb.append("return:unkown type ").append(ret.getClass());
        }
        sb.append("\n----\n\n\n");
        log.debug(sb);
    }

    @AfterThrowing(pointcut = "webLog()", throwing = "e")
    public void afterThrowing(Exception e) {
        StringBuilder sb = getThreadStringBuilder();
        log.debug(sb);
//        e.printStackTrace();
//        System.out.println("----------error-----------");
    }

}